import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;

public class Line extends DrawObject
{
	// DrawObject abilities:
	@Override
	public boolean IsLine()
	{
		return true;
	}

	@Override
	public boolean CanBeMovedByUser()
	{
		return false;
	}

	@Override
	public boolean CanBeSelectedByUser()
	{
		return true;
	}

	@Override
	public boolean CanBeDeletedByUser()
	{
		return true;
	};

	@Override
	public boolean CanBeExcitedByUser()
	{
		return false;
	};
	// end of DrawObject abilities

	private DrawObject StartDrawObject;
	private DrawObject EndDrawObject;

	public Line(DrawObject StartDrawObject, DrawObject EndDrawObject)
	{
		SetPos(new Point(0, 0)); // dummy Pos and Size, drawn with StartDrawObject and EndDrawObject information only
		SetSize(new Point(0, 0)); // dummy Pos and Size, drawn with StartDrawObject and EndDrawObject information only
		InitializeExcitement(ExcitementOnceMilliseconds);

		this.StartDrawObject = StartDrawObject;
		this.EndDrawObject = EndDrawObject;
	};

	private double DistanceToPoint(Point pt1, Point pt2, Point pt3)
	{
		// maybe a bit complicated but better understandable
		// (see website) and works well

		int Minx = 0;
		int Maxx = 0;

		if (pt1.x <= pt2.x)
		{
			Minx = pt1.x;
			Maxx = pt2.x;
		}
		if (pt1.x >= pt2.x)
		{
			Minx = pt2.x;
			Maxx = pt1.x;
		}

		int Miny = 0;
		int Maxy = 0;

		if (pt1.y <= pt2.y)
		{
			Miny = pt1.y;
			Maxy = pt2.y;
		}
		if (pt1.y >= pt2.y)
		{
			Miny = pt2.y;
			Maxy = pt1.y;
		}

		if ((Maxx - Minx < 50 || (pt3.x >= Minx && pt3.x <= Maxx)) && (Maxy - Miny < 50 || pt3.y >= Miny && pt3.y <= Maxy))
		{
			// https://studyflix.de/mathematik/hohe-dreieck-berechnen-4759, altered

			double c = Math.sqrt((pt2.x - pt1.x) * (pt2.x - pt1.x) + (pt2.y - pt1.y) * (pt2.y - pt1.y));
			double a = Math.sqrt((pt3.x - pt1.x) * (pt3.x - pt1.x) + (pt3.y - pt1.y) * (pt3.y - pt1.y));
			double b = Math.sqrt((pt2.x - pt3.x) * (pt2.x - pt3.x) + (pt2.y - pt3.y) * (pt2.y - pt3.y));

			double s = 0.5 * (a + b + c);

			double hc = 2.0 / c * Math.sqrt(s * (s - a) * (s - b) * (s - c));

			return hc;
		}
		else
		{
			return Double.MAX_VALUE;
		}
	}

	@Override
	public void Draw(Graphics g)
	{
		if (!(IsWithinWindowBounds(this, 0)))
			return;

		// draw single line
		if (IsHighlighted || IsPartOfMultiSelection)
			SetColor(g, Color.GREEN);
		else if (IsCommentField)
			SetColor(g, GetExcitementColor(Color.BLUE));
		else
			SetColor(g, GetExcitementColor(Color.RED));

		int LineStartPosx = StartDrawObject.Pos.x + StartDrawObject.Size.x / 2;
		int LineStartPosy = StartDrawObject.Pos.y + StartDrawObject.Size.y / 2;
		int LineEndPosx = EndDrawObject.Pos.x + EndDrawObject.Size.x / 2;
		int LineEndPosy = EndDrawObject.Pos.y + EndDrawObject.Size.y / 2;

		if (IsCommentField)
			DrawThickLine(
				// if changing this (draw to CENTER), update also GetDistanceToPoint()!
				g, LineStartPosx, LineStartPosy, LineEndPosx, LineEndPosy
			);
		else
			DrawLine(
				// if changing this (draw to CENTER), update also GetDistanceToPoint()!
				g, LineStartPosx, LineStartPosy, LineEndPosx, LineEndPosy
			);

		// draw a little rect as sign for orientation (flow is conducted only in one direction)
		if (!(IsCommentField))
		{
			double Factor = 0.8;

			FillRect(g, (int) (LineStartPosx + (LineEndPosx - LineStartPosx) * Factor - 1), (int) (LineStartPosy + (LineEndPosy - LineStartPosy) * Factor - 1), 3, 3);
		}
	}

	public double GetDistanceToPoint(Point P)
	{
		// ATTENTION: Line goes into CENTER of [Start/End]DrawObject!
		// We NEED to take this into account or Lines are not selected
		// precisely (tested)!

		return DistanceToPoint(
			new Point(StartDrawObject.Pos.x + StartDrawObject.Size.x / 2, StartDrawObject.Pos.y + StartDrawObject.Size.y / 2), new Point(EndDrawObject.Pos.x + EndDrawObject.Size.x / 2, EndDrawObject.Pos.y + EndDrawObject.Size.y / 2), P
		);
	}

	public DrawObject GetEndDrawObject()
	{
		return EndDrawObject;
	}

	public DrawObject GetStartDrawObject()
	{
		return StartDrawObject;
	}

	public void SetEndDrawObject(DrawObject EndDrawObjectNew)
	{
		if (EndDrawObjectNew != null)
			EndDrawObject = EndDrawObjectNew;
		else
			System.out.println("error in Line.SetEndrawObject(): passed value not useful!");
	}

	public void SetStartDrawObject(DrawObject StartDrawObjectNew)
	{
		if (StartDrawObjectNew != null)
			StartDrawObject = StartDrawObjectNew;
		else
			System.out.println("error in Line.SetStartDrawObject(): passed value not useful!");
	}
}
